/**
 * Copyright (C) 2012-2013 jumei, Inc.
 * ClientProxyBeanInvokHandler.java
 * 2015年6月24日
 */
package org.goface.rpc;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import org.goface.rpc.pipeline.ServicePipeLine;
import org.goface.rpc.pipeline.ServicePipeLineFactory;

import com.goface.rpc.conf.ServiceConfigure;
import com.goface.rpc.conf.ServiceConfigureCenter;

/**
 * @author jm110
 */
public class ClientProxyBeanInvocationHandler implements InvocationHandler {
    private ServicePipeLine servicePipeLine;
    private String serviceId;
    private AtomicLong  messageId=new AtomicLong(1);
    // 为方便配置的动态修改，这里不直接持有服务的配置实例，只保持配置中心的引用，由配置中心解决配置更新和缓存
    private ServiceConfigureCenter configureCenter;

    public ClientProxyBeanInvocationHandler(String serviceId, ServiceConfigureCenter configureCenter) {
        this.serviceId = serviceId;
        servicePipeLine = ServicePipeLineFactory.createClientSidePipeLine();
        this.configureCenter = configureCenter;

    }


    /*
     * (non-Javadoc)
     *
     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
     * java.lang.reflect.Method, java.lang.Object[])
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("toString".equals(method.getName())) {
            return "client-proxy";
        }
        ServiceConfigure configure = configureCenter.getServiceConfigure(serviceId);
        MessageContext request = encodeMessage(method, args, configure);
        boolean isOneway = method.getReturnType().equals(Void.TYPE);
        request.getProperties().put(ServiceConfigure.SERVICE_CLIENT_OP_ONEWAY, isOneway);
        servicePipeLine.fireSendRequest(request);
        Object ret = request.getRetFuture().get().getReply();
        return ret;
    }

    private MessageContext encodeMessage(Method method, Object[] args,
			ServiceConfigure configure) {
		String operator = method.getName();
		Message message = new Message();
		message.setId(messageId.getAndIncrement()+"");
		message.setArgs(args);
		message.setOperator(operator);
		message.setServiceName(configure.getServiceRef());
		MessageContext context = new MessageContext();
		context.setMessage(message);
		Map<String, Object> properties = new HashMap<String, Object>(
				configure.getProperties());
		properties.put(MessageContext.MESSAGE_TYPE, MessageContext.MESSAGE_TYPE_REQUEST);
		context.setProperties(properties);
		return context;

	}
}
